package synapsolution;

public class PrimeNetwork extends Network implements Comparable<Network> {

    Layer output = new Layer(7);
    Layer middle = new Layer(10, output);
    Layer input = new Layer(5, middle);
    static int[] primes = new int[]{0, 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127};
    // 0 is only included because 2 is the first prime number and hence should be element 1, not 0. Element 0 should never be tested.

    public PrimeNetwork(PrimeNetwork a, PrimeNetwork b) {
        assert (a != b);
        if (Population.showCombinations) System.out.println("*** Combining networks\n" + a + "\n" + b);
        middle.combine(a.middle, b.middle);
        input.combine(a.input, b.input);
        if (Population.showCombinations) System.out.println("Results!:\n" + this);
    }

    public PrimeNetwork() {
    }

    @Override
    int process(int n) {
        for (int i = 1; i <= n; i <<= 1) if ((n & i) != 0) input.get((int) (Math.log(i) / Math.log(2))).fire();
        for (Neuron neuron : middle) neuron.checkFire();
        for (Neuron neuron : output) neuron.checkFire();
        int out = 0;
        for (int i = 0; i < output.size(); i++) if (output.get(i).activated) out |= 1 << output.size() - i;
        output.deactivate();
        middle.deactivate();
        return out;
    }

    @Override
    int fitness() {
        int errors = 0;
        for (int i = 1; i < 1 << input.size(); i++) errors += Math.pow(Integer.bitCount(process(i) ^ primes[i]), 2);
        if (errors == 0) {
            System.out.println("This network has learned the prime number function.\n\n" + toString());
            System.exit(0);
        }
        return errors;
    }

    @Override
    public String toString() {
        return "Weights of the input layer\n" + input + "\nWeights of the middle layer\n" + middle;
    }
}
